import ogre.renderer.OGRE as ogre
import random


class Spritesheet:
    """This class represents a Spritesheet. A Spritesheet is a sequence of unique frames defined from a texture that has equal or greater dimension than this Spritesheet."""
    def __init__(self, sceneManager, textureName, region, numRow, numCol, isHenchmen=True):
        """Constructor
        
        This constructor will construct this Spritesheet. 
        
        Args:
            sceneManager: A valid ogre scene manager.
            textureName: the name of the parent texture backing this spritesheet.
            region: the region within parent texture used to construct the sequence of frames.
            numRow: number of rows of the given region. This is used to define number of frames per row.
            numCol: number of columns of the given region. This is used to define number of frames per column.
        
        """
        self.texture = ogre.TextureManager.getSingleton().getByName(textureName)
        if self.texture is None:
            self.texture = ogre.TextureManager.getSingleton().load(textureName, ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME)
        
        #origin starts at top left.
        uvRects = []
        dCol = (region[2] / numCol) / self.texture.width #region[2] is width
        dRow = (region[3] / numRow) / self.texture.height
        self.frames = []
        unitFrame = ogre.Vector2(dCol, dRow)
        sequenceOrigin = ogre.Vector2(region[0] / self.texture.width, region[1] / self.texture.height)
        for j in range(0, numRow):
            for i in range(0, numCol):
                nthOrigin = ogre.Vector2(i * dCol, j * dRow)
                frameS = sequenceOrigin + nthOrigin 
                frameE = sequenceOrigin + nthOrigin + unitFrame
                uvRects.append(ogre.FloatRect(frameS.x, frameS.y, frameE.x, frameE.y))
                self.frames.append(j * numRow + i)
        
        material = ogre.MaterialManager.getSingleton().getByName("BTFX/Billboard2d").clone("BTFX/Billboard2d/"+textureName)
        material.getTechnique(0).getPass(0).getTextureUnitState(0).setTextureName(self.texture.getName())
        
        self.billboardSet = sceneManager.createBillboardSet()
        #self.billboardSet.setMaterialName(self.material.getName())
        self.billboardSet.setMaterialName(material.getName())
        
        self.billboardSet.setTextureCoords(uvRects)
        bounds = ogre.AxisAlignedBox(ogre.AxisAlignedBox.EXTENT_INFINITE)
        self.billboardSet.setBounds(bounds, 1.0)
        
        
        if isHenchmen:
            self.billboardSet.setRenderQueueGroup(ogre.RENDER_QUEUE_OVERLAY)
        else:
            material.setDepthCheckEnabled(True)
            material.setDepthWriteEnabled(True)
        
        #material = ogre.MaterialManager.getSingleton().getByName("BillboardMatDynamic").clone("BillboardMatDynamic/"+textureName)
        #material.getTechnique(0).getPass(0).createTextureUnitState().setTextureName(self.texture.getName())
        
        
class AnimatedSprite:
    """
    A Sprite class that is backed by ogre.BillboardSets with unique animation frames.
    """
    def __init__(self, node, billboard, dimension, frames, duration=1.0, pos=ogre.Vector3(0.0, 0.0, 0.0), xOffset = 0.0, yOffset = 0.0, zOffset = 0.0):
        self.offset = ogre.Vector3(xOffset, yOffset, zOffset)
        self.node = node
        self.pos = pos #position are in world space
        self.billboard = billboard
        self.billboard.setDimensions(dimension[0], dimension[1])
        self.billboard.setPosition(self.pos)
        self.duration = duration
        #init to first frame.
        self.billboard.setTexcoordIndex(frames[0])
        self.frames = frames
        self.elapsedTime = 0.0
        self.numOfFrames = len(self.frames)
        self.framecount = 0
        self.horizontalVelocity = ogre.Vector3(1.0, 0.0, 0.0)
        self.orientation = ogre.Quaternion()
        self.randomTime = 0.0
        return None
    
    def updatePosition(self, positionChange):
        self.pos += positionChange
        self.node.setPosition(self.pos + self.offset)
    def setPosition(self, position):
        self.pos = position
        self.node.setPosition(self.pos + self.offset)        
    def update(self, dt):
        if(self.elapsedTime > self.duration):
            self.elapsedTime = 0.0
            self.framecount += 1
            self.billboard.setTexcoordIndex(self.framecount % self.numOfFrames)
        self.elapsedTime += dt
        self.node.setPosition(self.pos + self.offset)
        self.billboard.setPosition(self.node.getPosition())
        return None

    
class SpriteManager:
    def __init__(self, sceneManager, cameraNode):
        #define the henchmen spritesheets
        self.sceneManager = sceneManager
        henchmenParams = {"dimension": [1.5, 1.5]}
        neiDefine = ["sprites_nei_trans.tga", [0.0, 0.0, 55.0, 2.0 * 55.0]] 
        #rolfSpriteSheet.height - 55, 65 * 3, 55
        rolfDefine = ["sprites_rolf_trans.tga", [0.0, 0.0, 3.0 * 64.0, 55.0]]
        
        eyeSoreParams = {"dimension": [3.0, 3.0], "yoffset": 2.0}
        eyeSoreStrongParams = {"dimension": [6.0, 6.0], "yoffset": 1.0}
        eyeSoreWeak = ["EyeSoreWeak", "eyesore.tga", [0.0, 0.0, 102.0*3.0, 96.0], (1, 3), eyeSoreParams]
        eyeSoreStrong = ["EyeSoreStrong", "eyesore.tga", [0.0, 96.0, 102.0*3.0, 96.0 * 3], (2, 3), eyeSoreStrongParams]
        eyeSoreNormal = ["EyeSoreNormal", "eyesore.tga", [0.0, 96.0*3, 102.0*3.0, 96.0 * 4], (1, 3), eyeSoreStrongParams]
        
        enemiesDefines = [eyeSoreWeak, eyeSoreStrong, eyeSoreNormal]
            
        self.henchmen = {}
        self.spritesheetNei = Spritesheet(sceneManager, neiDefine[0], neiDefine[1], 2, 1)
        
        billboard = self.spritesheetNei.billboardSet.createBillboard(ogre.Vector3(0.0, 0.0, 0.0))
        cameraNode.attachObject(self.spritesheetNei.billboardSet)
        
        node = self.sceneManager.getRootSceneNode().createChildSceneNode()
        
        self.henchmen["NeiHenchmen"] = (AnimatedSprite(node, billboard, henchmenParams['dimension'], self.spritesheetNei.frames, duration=0.1))
        
        self.spritesheetRolf = Spritesheet(sceneManager, rolfDefine[0], rolfDefine[1], 1, 3)
        billboard = self.spritesheetRolf.billboardSet.createBillboard(ogre.Vector3(0.0, 0.0, 0.0))
        
        cameraNode.attachObject(self.spritesheetRolf.billboardSet)
        
        node = self.sceneManager.getRootSceneNode().createChildSceneNode()
        
        self.henchmen["RolfHenchmen"] = (AnimatedSprite(node, billboard, henchmenParams['dimension'], self.spritesheetRolf.frames, duration=0.5))
        
        self.enemiesMap = {}
        node = sceneManager.getRootSceneNode().createChildSceneNode()
        for enemy in enemiesDefines:
            spriteSheet = Spritesheet(sceneManager, enemy[1], enemy[2], enemy[3][0], enemy[3][1], False)
            self.enemiesMap[enemy[0]] = {"spritesheet": spriteSheet, "params": enemy[4]}
            node.attachObject(spriteSheet.billboardSet)       
        return
    
    def createEnemies(self, listOfEnemies):
        enemySprites = []
        for item in listOfEnemies:
            enemy = item[0]
            posv = item[1]
            enemyItem = self.enemiesMap[enemy]
            spritesheet = enemyItem["spritesheet"]
            billboard = spritesheet.billboardSet.createBillboard(ogre.Vector3())
            node = self.sceneManager.getRootSceneNode().createChildSceneNode()
            yOffset = enemyItem["params"]["yoffset"]
            enemySprites.append(AnimatedSprite(node, billboard, enemyItem["params"]["dimension"], spritesheet.frames, duration=0.5, pos=ogre.Vector3(posv.x, posv.y, posv.z), yOffset=yOffset))
        
        return enemySprites
    
    def getHenchmen(self, name):
        return self.henchmen[name]